[1/3] arch/xtensa: Provide vfork() - #19795
Conversation
|
87d1d68 to
af62cf0
Compare
af62cf0 to
27547e0
Compare
🔗 Cross-repo PR dependenciesThe read-only Build run reported the following dependent PR(s) and fetched head SHA(s): CI run: https://github.com/apache/nuttx/actions/runs/31531206452 |
❌ Cross-repo dependency could not be appliedThe Build report says the declared dependency PR(s) could not be applied, so CI did not run against the combined code: Reason: cherry-pick failed (if your PR has merge commits, rebase instead) CI run: https://github.com/apache/nuttx/actions/runs/32367174417 |
e6cdfde to
25066b2
Compare
| * this is how it reaches the registers of the thread that called it. | ||
| */ | ||
|
|
||
| tcb->xcp.sregs = regs; |
There was a problem hiding this comment.
but tcb->xcp already save regs?
There was a problem hiding this comment.
yes, xcp.regs holds it during the exception, but xtensa_irqdispatch.c sets it back to NULL on the way out, "to avoid misusage".
up_fork is itself the syscall, so its body runs as normal C after the exception has returned, and xcp.regs is NULL by then. that is what sregs is for anyway, right?
it is the same thing armv7-a does, arm_syscall.c sets rtcb->xcp.sregs = regs and arch/arm/include/armv7-a/irq.h declares the field.
I will move it into the default case and guard it the same way as arm.
Xtensa selected neither fork primitive, so vfork() was simply absent. This wires it onto the two-primitive semantics. There is no assembly entry point and none is needed. Every exception entry already runs SPILL_ALL_WINDOWS, so the whole context of the calling thread is in its exception frame and copying its stack copies a complete frame chain. A flat build reaches that frame through SYS_save_context, issued inline so that the recorded stack pointer belongs to a frame that stays alive for the whole operation; a build with syscalls reaches it through xcp.sregs, recorded by xtensa_swint() for the duration of the call. The stack copy needs more than a relocated stack pointer here. A windowed ABI stores each frame's caller stack pointer absolutely, in the base save area below the frame, so a copy taken at a different address still names the parent throughout and the child's first retw would underflow onto the parent's stack. xtensa_fork_rebase() walks that chain and adds the relocation offset to each link. The copy also starts one base save area below the stack pointer rather than at it, because the frame the child resumes into keeps its caller's spilled a0-a3 there. Ported from the per-architecture work, reduced to the two primitives. Co-authored-by: Xiang Xiao <xiaoxiang781216@gmail.com> Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
25066b2 to
a931ae3
Compare
Summary
Split from #19772, part 1 of 3, as asked in review.
It gives Xtensa
vfork()and nothing else. No MMU, no address environment, no chip code.up_fork(bool vfork)is the architecture half of the primitive introduced by #19562. The child gets its own stack holding a relocated copy of the part of the parent's that is in use, and resumes where the caller would have returned.Two paths reach it. A flat build calls in directly, so the caller's registers are taken at the call. A build with system calls arrives through
xtensa_swint(), which has already recorded the caller's frame inxcp.sregs; that frame is used instead, because the caller is on the far side of the boundary.The windowed ABI needs care in one place. A stack pointer has a base save area 16 bytes below it holding the caller's spilled
a0–a3, and the frame chain runs through it.SPILL_ALL_WINDOWSputs the register file into memory first, and the chain is then walked and rebased onto the child's copy, because a frame pointer that still points into the parent's stack would send the child back into memory it does not own.Impact
Xtensa gains
vfork(). Nothing else changes, and no board configuration changes.fork()is not provided here. That needs an address environment and arrives in part three.Testing
Host: macOS 15 on Apple Silicon,
xtensa-esp32s3-elf-gccandxtensa-esp32-elf-gcc, both 12.2.0.Three boards ran
ostestto the end.esp32-devkitc:ostestvfork()passes, status 0esp32s3-devkit:ostestvfork()passes, status 0esp32s3-devkit:ostestvfork()passes, status 0The 32 MB octal part also needs
ESP32S3_FLASH_MODE_OCTandESP32S3_SPI_FLASH_USE_32BIT_ADDRESS.Both Xtensa cores that NuttX supports are covered, and the LX6 has no MMU at all — which is the case this part is meant to serve.
tools/checkpatch.sh -c -u -m -greports no errors.The ostest split this needs, apache/nuttx-apps#3685, is merged, so the
depends-online is gone.